package com.smasher.update

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.text.TextUtils
import android.util.Log
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.smasher.core.log.ToastUtil
import com.smasher.update.component.check.CheckInfoImplSoftOut
import com.smasher.update.component.download.DownloadFinishListener
import com.smasher.update.component.download.sys.DownloadImplSystem
import com.smasher.update.component.parse.OnParseListener
import com.smasher.update.component.parse.ParseImplSoftOut
import com.smasher.update.component.update.ExecutorBuilder
import com.smasher.update.component.update.UpdateExecutor
import com.smasher.update.dialog.UpdateVersionDialog
import com.tencent.mmkv.MMKV
import java.lang.ref.WeakReference


open class UpdateHelper(
    context: FragmentActivity,
    private val channel: String,
    private val code: Long
) : DefaultLifecycleObserver {

    private val supportFragmentManager: FragmentManager = context.supportFragmentManager
    private val executor: UpdateExecutor
    private var forceUpdate = false
    private var weakReference: WeakReference<Context> = WeakReference(context)

    private val mmkv: MMKV by lazy {
        MMKV.mmkvWithID(UPDATE_IGNORE)
    }

    private val parseListener = object : OnParseListener {
        override fun onParse(
            title: String,
            description: String,
            versionCode: Long,
            type: String,
            url: String,
            time: Long
        ) {
            afterParse(title, description, versionCode, type, url, time)
        }
    }

    private val downloadFinishListener =
        object : DownloadFinishListener {
            override fun onDownload(id: Long) {
                doAfterDownload(id)
            }
        }

    init {
        val rootDir = MMKV.initialize(context)
        Log.d(TAG, "MMKV rootDir: $rootDir")
        executor = ExecutorBuilder(context)
            .initVersionCheckDelegate(CheckInfoImplSoftOut(context))
            .initParseDelegate(ParseImplSoftOut())
            .initDownloadDelegate(DownloadImplSystem(context))
            .setDownloadFinishListener(downloadFinishListener)
            .setParseListener(parseListener)
            .create()
        context.lifecycle.addObserver(this)
    }


    /**
     * 强制检查更新
     * @param context context
     */
    fun checkVersion(context: Context) {
        checkVersion(context, true)
    }

    /**
     * 强制检查更新
     * @param context context
     * @param silent 是否静默 用于控制是否显示toast
     */
    fun checkVersion(
        context: Context,
        silent: Boolean
    ) {
        checkVersion(context, silent, false)
    }

    /**
     * 强制检查更新
     * @param context context
     * @param silent 是否静默 用于控制是否显示toast
     * @param force 是否强制显示更新
     */
    fun checkVersion(
        context: Context,
        silent: Boolean,
        force: Boolean
    ) {
        forceUpdate = force
        executor.checkVersion(channel, code, silent)
    }


    fun checkVersionOnly(
        context: Context,
        silent: Boolean,
        callback: (Long) -> Unit
    ) {
        executor.checkVersionOnly(channel, code, silent, callback)
    }

    open fun afterParse(
        title: String,
        description: String,
        versionCode: Long,
        type: String,
        url: String,
        time: Long
    ) {
        Log.d(TAG, "afterParse: ")
        if (TextUtils.isEmpty(url)) {
            return
        }
        val ignoreVersionCode = mmkv.decodeLong(UPDATE_IGNORE_VERSION, 0L)
        if (forceUpdate) {
            showUpdateDialog(
                title, description, versionCode, type, url, time
            )
        } else {
            if (versionCode > code) {
                when {
                    versionCode > ignoreVersionCode ->
                        showUpdateDialog(
                            title, description, versionCode, type, url, time
                        )

                    else -> {
                        //do nothing
                    }
                }
            }
        }
    }


    fun doAfterDownload(id: Long) {
        Log.d(TAG, "onDownload: $id")
        ToastUtil.info(weakReference.get(), "下载完成")

        try {
            val finished = executor.queryFinishedById(id)
            Log.d(TAG, "is finished: $finished")

            val localUri = executor.getDownloadUriById(id)
            Log.d(TAG, "info: $localUri")
            if (localUri != null) {
                weakReference.get()?.let {
                    installApk(it, localUri)
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "error: $e")
        }
    }


    /**
     * 显示更新对话框
     * @param context 上下文
     */
    private fun showUpdateDialog(
        title: String,
        description: String,
        versionCode: Long,
        type: String,
        url: String,
        time: Long
    ) {
        var fragment = supportFragmentManager.findFragmentByTag(FRAGMENT_UPDATE_TAG)
        if (fragment == null) {
            fragment = UpdateVersionDialog.newInstance()
        }
        if (fragment is UpdateVersionDialog) {
            fragment.initTitleContent(title, description, "", url, versionCode.toString())
            fragment.setUpdateListener(updateListener)
            if (!fragment.isShowing()) {
                fragment.show(supportFragmentManager, FRAGMENT_UPDATE_TAG)
            }
        }
    }


    private val updateListener = object : UpdateVersionDialog.OnUpdateListener {
        override fun gotoDownload(url: String) {
            downloadUrl(url)
        }

        override fun nextTime() {

        }

        override fun ignoreVersion(versionCode: Long) {
            when (versionCode) {
                0L -> mmkv.removeValueForKey(UPDATE_IGNORE_VERSION)
                else -> mmkv.encode(UPDATE_IGNORE_VERSION, versionCode)
            }
        }
    }

    /**
     * 安装apk
     */
    private fun installApk(context: Context, uri: Uri) {

        val typeApk = "application/vnd.android.package-archive"

        val intent = Intent(Intent.ACTION_VIEW)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.setDataAndType(uri, typeApk)

        if ((Build.VERSION.SDK_INT >= 24)) {//版本是否在7.0以上
//            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            intent.addFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
            )
            intent.addCategory("android.intent.category.DEFAULT")
            //对目标apk的uri临时授权 使得有权限打开该Uri指向的Apk
        } else {
            intent.addCategory("android.intent.category.DEFAULT")
        }
        context.startActivity(intent)
    }

    /**
     * 下载apk
     */
    fun downloadUrl(url: String) {
        Log.d(TAG, url)
        executor.downloadByUrl()
    }

    /**
     * 释放资源
     */
    fun release(context: Context) {
        weakReference.clear()
        executor.release()
    }

    override fun onDestroy(owner: LifecycleOwner) {
        weakReference.clear()
        executor.release()
    }

    companion object {
        const val TAG = "Main"
        const val FRAGMENT_UPDATE_TAG = "update_version"
        const val UPDATE_IGNORE = "UPDATE_IGNORE"
        const val UPDATE_IGNORE_VERSION = "UPDATE_IGNORE_VERSION"
    }
}
